home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Utilities
/
Programming
/
EnterAct 3.7.3
/
Read Res project
/
Read_Res Source
/
Read_Res.c
< prev
Wrap
Text File
|
1994-12-22
|
13KB
|
478 lines
/* Read_Res.c - reads a specific resource from a file, and sends
a formatted text version to the standard out file.
Retrieves entire data fork if you specify resource type 'data', id 0.
Shows hex and ascii values in a double-wide format. Note some example
hAWK programs, eg $Print_MENU_Resource, illustrate analyzing the result
from Read Resource - format the output, verify resource format. */
/* Copyright © 1991 the Free Software Foundation, Inc.
* This file is free software; you can redistribute or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or any later version.
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file "COPYING hAWK". If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
*/
#include "CodeResource.h"
#include "AppCodeComm.h"
#include "CodeResHelper.h"
#include "CodeResFiles.h"
#include <string.h>
//#if THINK_C >= 5
//pascal void StringToNum(char *theString,long *theNum);
//pascal void NumToString(long theNum,char *theString);
//#endif
#define LoadResID 406
short DoReadRes(void);
pascal short XferHookPick(short item, DialogPtr dlog);
Boolean ResForkIsAlreadyOpen(StringPtr fName, short vRefNum);
Boolean SpecifyResource(long *theTypePtr, short *theIDPtr);
Boolean BadIDNumber(char *idStr);
Handle ReadTheResource(StringPtr namePtr, short vref, long theType, short theID);
Handle ReadDataFork(StringPtr namePtr, short vref);
Handle FixUpResource(Handle rawH);
void WriteCharToOutput( char theChar);
void JumpOnError(void);
/* Ask user to pick file, specify resource type and id. Print resource as hex
and ascii to stdout. Return 1 (show resulting stdout) or -1 (error). */
short DoReadRes()
{
Point where;
SFReply reply;
SFTypeList types;
Handle hText;
long theType;
short theID, ret = -1;
/* calculate where to put dialog, so that it'll be centered */
GetDlogOrigin (getDlgID, &where);
do
{
SFGetFile (where, (StringPtr)"", NULL, -1, types, XferHookPick, &reply);
} while (reply.good && ResForkIsAlreadyOpen((StringPtr)(reply.fName), reply.vRefNum));
/* If cancelled, forget it */
if (!reply.good)
return(-1);
if (!SpecifyResource(&theType, &theID)) return(-1);
/* Read in the resource and write it to stdout */
if (hText = ReadTheResource ((StringPtr)(reply.fName), reply.vRefNum,theType, theID))
{
hText = FixUpResource(hText);
if (hText)
{
if (PutToStdOut(hText))
ret = 1;
DisposHandle(hText);
}
else
OKStopAlert("Not quite enough memory to do that, sorry.");
}
return(ret);
}
/* Change name of open button */
pascal short XferHookPick(short item, DialogPtr dlog)
{
short theType;
Handle theItem;
Rect theBox;
char pick[5];
if (item == -1)
{
pick[0] = 4;
pick[1] = 'P';
pick[2] = 'i';
pick[3] = 'c';
pick[4] = 'k';
GetDItem (dlog, getOpen, &theType, &theItem, &theBox);
SetCTitle ((ControlHandle)theItem, (StringPtr)pick);
}
return (item);
}
/* Prelim assume that if youve seen one vref youve seen them all.
Seems that PBGetFCBInfo never sets ioVRefNum, tho perhaps it
pays attention to it...ioFCBVRefNumis for some reason set
to the root of the disk. The awkward solution is to determine
the owning directory ID of the file, and index thru open files,
checking those that have the same dirID. */
Boolean ResForkIsAlreadyOpen(StringPtr fName, short vRefNum)
{
FCBPBRec pb;
WDPBRec theParms;
short parentID;
char fileName[32];
Boolean resFAlreadyOpen = FALSE;
theParms.ioVRefNum = vRefNum;
theParms.ioNamePtr = NULL;
theParms.ioWDIndex = 0;
theParms.ioWDProcID = 0;
if (PBGetWDInfo(&theParms, FALSE)) /* trouble of some kind */
return(TRUE);
parentID = theParms.ioWDDirID;
pb.ioCompletion = NULL;
pb.ioNamePtr = (StringPtr)fileName;
pb.ioVRefNum = vRefNum;
pb.ioRefNum = 0;
pb.ioFCBIndx = 1;
while (!PBGetFCBInfo(&pb, FALSE))
{
if ((short)(pb.ioFCBParID) == parentID)
{
if (PEqualStrs((Byte *)fileName, (Byte *)fName))
{
resFAlreadyOpen = TRUE;
break;
}
}
pb.ioVRefNum = vRefNum;
pb.ioRefNum = 0;
pb.ioFCBIndx += 1;
}
if (resFAlreadyOpen)
{
OKStopAlert("Please avoid files that are already open.");
return(TRUE);
}
return(FALSE);
}
/* This should really have popup menus for the resource type and id. */
Boolean SpecifyResource(long *theTypePtr, short *theIDPtr)
{
register DialogPtr dPtr;
Ptr tempPtr;
short itemHit, theType, i, numTries;
Handle theItem;
Rect theBox;
char typeStr[10], idStr[10];
long idNum;
InitCursor ();
if (!GetAndAlignDialog(LoadResID))
return(FALSE);
dPtr = GetNewDialog (LoadResID, NULL, (WindowPtr)-1L);
numTries = 6;
FrameDialogItem(dPtr,1);
do{
--numTries;
SelIText (dPtr, 5, 0, 502);
/* Give user a chance to change it and see if it's ok */
ModalDialog (NULL, &itemHit);
if (itemHit == Cancel)
break;
GetDItem (dPtr, 5, &theType, &theItem, &theBox);
GetIText (theItem, (StringPtr)typeStr);
GetDItem (dPtr, 6, &theType, &theItem, &theBox);
GetIText (theItem, (StringPtr)idStr);
StringToNum ((StringPtr)idStr, &idNum);
} while ((BadIDNumber(idStr) || typeStr[0] != 4) && numTries >= 0);
/* If cancelled, don't do anything */
if (itemHit == Cancel || numTries < 0)
{
DisposDialog (dPtr);
return(FALSE);
}
tempPtr = (Ptr)theTypePtr;
for (i = 0; i < 4; ++i)
*(tempPtr + i) = *(typeStr + i + 1);
*theIDPtr = (short)idNum;
DisposDialog (dPtr);
return(TRUE);
}
/* Return TRUE if id number is BAD.
Leading white space not allowed.*/
Boolean BadIDNumber(char *idStr)
{
short i, len = idStr[0];
Boolean minusSeen = FALSE;
if (len < 0 || len > 6) return(TRUE);
for (i = 1; i <= len; ++i)
{
if (idStr[i] == '-')
{
if ( i != 1)
return(TRUE);
else
minusSeen = TRUE;
}
else if (idStr[i] < '0' || idStr[i] > '9')
return(TRUE);
}
if (!minusSeen && len == 6) return(TRUE);
return(FALSE);
}
/* Get the specified resource. Due to overwhelming demand, also read in
the data fork if wanted - this specified as 'data' id 0. */
Handle ReadTheResource(StringPtr namePtr, short vref, long theType, short theID)
{
short saveVol, refNum;
Handle rsrcHandle, theHdle = NULL;
long itemSize;
short tempfNum;
if (theType == 'data' && !theID) /* data fork requested */
return(ReadDataFork(namePtr, vref));
tempfNum = CurResFile();
/* Remember default volume before changing it */
if (GetVol (NULL, &saveVol))
saveVol = 0;
/* And set the volume. This must be done because OpenResFile
looks only in current volume (directory). Actually, it will
look along the Poor Man's Search Path, but this should do */
SetVol (NULL, vref);
SetResLoad(FALSE);
if ((refNum = OpenResFile (namePtr)) != -1)
{
SetResLoad(TRUE);
rsrcHandle = Get1Resource (theType, theID);
if (rsrcHandle)
{
itemSize = GetHandleSize(rsrcHandle);
theHdle = NewHandle(itemSize);
if (MemError() == noErr)
BlockMove(*rsrcHandle, *theHdle, itemSize);
else
{
ReleaseResource(rsrcHandle);
CloseResFile (refNum);
if (saveVol)
SetVol (NULL, saveVol);
UseResFile(tempfNum);
OKStopAlert("Sorry, not enough memory to get the resource.");
return(NULL);
}
ReleaseResource(rsrcHandle);
}
else
OKStopAlert("Sorry, no resource with that type and ID. \
Try using ResEdit to determine the correct type or number.");
CloseResFile (refNum);
}
else
{
SetResLoad(TRUE);
OKStopAlert("Sorry, couldn't open the resource fork \
- maybe there isn't one?.");
}
/* Restore default volume if any */
if (saveVol)
SetVol (NULL, saveVol);
UseResFile(tempfNum);
return(theHdle);
}
/* Read in the data fork to a handle. Note if there is
nothing in the file then NULL is returned rather than an empty
handle. */
Handle ReadDataFork(StringPtr namePtr, short vref)
{
Handle hText = NULL;
long count;
short saveVol, refNum;
Boolean opened = FALSE;
if (GetVol(NULL, &saveVol))
saveVol = 0;
if (FSOpen(namePtr, vref, &refNum))
goto JumpOut;
else
opened = TRUE;
if (GetEOF(refNum, &count) || count <= 0L)
goto JumpOut;
hText = NewHandle(count);
if (MemError() != noErr)
{
MemoryAlert();
goto JumpOut;
}
if (FSRead(refNum, &count, *hText))
{
DisposHandle(hText);
hText = NULL;
goto JumpOut;
}
JumpOut:
if (opened)
FSClose(refNum);
if (saveVol)
SetVol(NULL, saveVol);
return(hText);
}
#include <ctype.h>
#include <setjmp.h>
/* key code abbreviations - not all used here, but i thot you might like a list... */
#define ETX '\003' /* enter */
#define BS '\b' /* backspace */
#define HT '\t' /* tab */
#define CR 0x0D /* return */
#define ESC '\033' /* clear */
#define FS '\034' /* left arrow */
#define GS '\035' /* right arrow */
#define RS '\036' /* up arrow */
#define US '\037' /* down arrow */
#define COMMA ',' /* or 0x2C */
#define BLANK ' ' /* a space */
#define OPTBL ' ' /* option-space */
#define COLON ':'
#define FILLER '.' /* period, for nonascii char*/
#define StdHdleInc 1024L
static long outSize, privateTrueSize;
static Handle outH;
/* buffer holding position of long jump */
jmp_buf LREnvBuf;
Handle FixUpResource(Handle rawH)
{
long rawSize = GetHandleSize(rawH),
startSize = 3*rawSize,
rawPos = 0L;
Byte *rawBPtr;
Ptr rawPtr;
short byteOff, i, numPads, numDigits;
char rawChar, theChar, posStr[10];
Byte rawBChar;
MoveHHi(rawH);
HLock(rawH);
rawBPtr = (Byte *)(*rawH);
rawPtr = *rawH;
/* set up some convenient static stuff for creating new handle */
outSize = 0L;
privateTrueSize = 0L;
outH = NewHandle(startSize);
if (MemError() != noErr)
return(NULL);
privateTrueSize = startSize;
if (setjmp(LREnvBuf))
{
HUnlock(rawH);
DisposHandle(rawH);
DisposHandle(outH);
return(NULL);
}
/* output readable version of resource */
/* 16 bytes done per line; (8 hex space) 4 times, 16 ascii of same bytes. */
while (rawPos < rawSize)
{
/*WriteCharToOutput(HT); - for extra indent */
WriteCharToOutput(HT);
NumToString(rawPos, (StringPtr)posStr);
numDigits = posStr[0];
numPads = 5 - numDigits;
for (i = 0; i < numPads; ++i)
WriteCharToOutput(BLANK);
for (i = 1; i <= numDigits; ++i)
WriteCharToOutput(*(posStr + i));
WriteCharToOutput(COLON);
WriteCharToOutput(BLANK);
byteOff = 16;
if (rawPos + byteOff >= rawSize)
byteOff = rawSize - rawPos;
for (i = 0; i < byteOff; ++i)
{
if (i == 4 || i == 8 || i == 12)
WriteCharToOutput(BLANK);
rawChar = *(rawPtr + rawPos + i);
if ((theChar = ((rawChar >>4) & 15)) <= 9)
theChar += '0';
else
theChar += 'A' - 10;
WriteCharToOutput(theChar);
if ((theChar = ((rawChar) & 15)) <= 9)
theChar += '0';
else
theChar += 'A' - 10;
WriteCharToOutput(theChar);
}
/* take care of the last short line - pad it out if necessary so that
text over on the right will still line up with the lines above.
Revision, after some anguish, pad the last line with zeroes rather
than blanks, to simplify manipulating the results with a hAWK program. */
for (; i < 16; ++i)
{
if (i == 4 || i == 8 || i == 12)
WriteCharToOutput(BLANK);
WriteCharToOutput('0'); /* that's a zero */
WriteCharToOutput('0');
}
WriteCharToOutput(BLANK);
WriteCharToOutput(BLANK);
for (i = 0; i < byteOff; ++i)
{
rawBChar = *(rawBPtr + rawPos + i);
if (isprint(rawBChar))
WriteCharToOutput((char)rawBChar);
else
WriteCharToOutput(FILLER);
}
rawPos += 16L;
WriteCharToOutput(CR);
}
/* fix size of handle, dispose raw handle, return */
SetHandleSize(outH, outSize);
HUnlock(rawH);
DisposHandle(rawH);
return(outH);
}
void WriteCharToOutput( char theChar)
{
if (outSize >= privateTrueSize)
{
SetHandleSize(outH, privateTrueSize + StdHdleInc);
if (MemError() != noErr)
JumpOnError();
privateTrueSize += StdHdleInc;
}
*(*outH + outSize++) = theChar;
}
void JumpOnError()
{
longjmp(LREnvBuf, 1); /* return to save point */
}